package scatter.dict.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import scatter.common.rest.service.IBaseAddUpdateQueryFormServiceImpl;
import scatter.common.rest.validation.DictService;
import scatter.dict.pojo.dto.DictGroupItemDto;
import scatter.dict.pojo.form.*;
import scatter.dict.pojo.po.Dict;
import scatter.dict.rest.mapper.DictMapper;
import scatter.dict.rest.mapstruct.DictMapStruct;
import scatter.dict.rest.service.IDictService;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 * 字典表 服务实现类
 * </p>
 *
 * @author yw
 * @since 2020-11-25
 */
@Slf4j
@Service
@Transactional
public class DictServiceImpl extends IBaseAddUpdateQueryFormServiceImpl<DictMapper, Dict, DictAddForm, DictUpdateForm, DictPageQueryForm> implements IDictService, DictService {
    @Override
    public void preAdd(DictAddForm addForm,Dict po) {
        super.preAdd(addForm,po);
        po.setIsDisabled(false);
        if (!isStrEmpty(addForm.getCode())) {
            // 字典编码已存在不能添加
            assertByColumn(addForm.getCode(),Dict::getCode,false);
        }

    }

    @Override
    public void preUpdate(DictUpdateForm updateForm,Dict po) {
        super.preUpdate(updateForm,po);
        if (!isStrEmpty(updateForm.getCode())) {
            Dict byId = getById(updateForm.getId());
            // 如果字典编码有改动
            if (!isEqual(updateForm.getCode(), byId.getCode())) {
                // 字典编码已存在不能修改
                assertByColumn(updateForm.getCode(),Dict::getCode,false);
            }
        }

    }
    // 数据校验
    private void valid(Dict po){
        // 字典项下不能添加字典组
        String parentId = po.getParentId();

        if(isStrEmpty(parentId)){
            // 根节点只能是字典组
            Assert.isTrue(po.getIsGroup(),"字典项只能添加到字典组下面");
        }else{
            Dict byId = getById(parentId);
            Assert.notNull(byId,"父级不存在");
            Assert.isTrue(byId.getIsGroup(),"父级为字典项不能添加子节点");
        }
    }

    @Override
    public QueryWrapper<Dict> prepareQueryFormQueryWrapper(QueryWrapper<Dict> queryWrapper, DictPageQueryForm queryForm) {
        if (queryForm.getIsPublic() == null && queryForm.getIsIncludePublic() != null && queryForm.getIsIncludePublic()) {
            queryWrapper = convertEntityConditionToWrapper(queryWrapper);
            queryWrapper.lambda().or().eq(Dict::getIsPublic, true);
        }
        return queryWrapper;
    }

    @Override
    public List<Dict> getItemsByGroupCode(DictItemsQueryForm queryForm) {

        return getDict(queryForm,false);
    }

    /**
     * 提取公共方法
     * @param queryForm
     * @param isGroup
     * @return
     */
    private List<Dict> getDict(DictItemsQueryForm queryForm,boolean isGroup){
        Dict groupDict = getByCode(queryForm.getGroupCode());
        if (groupDict == null) {
            return new ArrayList<>(0);
        }

        List<Dict> result = list(Wrappers.<Dict>lambdaQuery()
                .eq(Dict::getParentId,groupDict.getId())
                .eq(!isStrEmpty(queryForm.getGroupFlag()),Dict::getGroupFlag,queryForm.getGroupFlag())
                .eq(Dict::getIsDisabled,false)
                .eq(Dict::getIsGroup,isGroup)
                .and(wp->{
                    wp.eq(Dict::getIsPublic,true).or().eq(!isStrEmpty(queryForm.getPrivateFlag()),Dict::getPrivateFlag,queryForm.getPrivateFlag());
                })
        );
        if (isStrEmpty(queryForm.getTags())) {
            return result;
        }
        List<String> paramTags = newArrayList(queryForm.getTags().split(","));

        // 过滤标签
        return result.stream().filter(dict ->
                !isStrEmpty(dict.getTags()) && newArrayList(dict.getTags().split(",")).stream().anyMatch(tag -> paramTags.contains(tag))
        ).collect(Collectors.toList());

    }

    @Override
    public List<DictGroupItemDto> getGroupItemsByGroupCode(DictItemsQueryForm queryForm) {
        Dict groupDict = getByCode(queryForm.getGroupCode());

        // 这里不考虑字典组的禁用和公共状态等
        List<Dict> groups = list(Wrappers.<Dict>lambdaQuery()
                .eq(Dict::getParentId,groupDict.getId())
                .eq(Dict::getIsGroup,true)
        );

        if (isEmpty(groups)) {
            return new ArrayList<>(0);
        }
        List<DictGroupItemDto> result = new ArrayList<>();
        DictGroupItemDto dictGroupItemDto = null;
        for (Dict group : groups) {
            dictGroupItemDto = DictMapStruct.INSTANCE.poToDictGroupItemDto(group);
            queryForm.setGroupCode(dictGroupItemDto.getCode());
            List<Dict> itemsByGroupCode = getItemsByGroupCode(queryForm);
            if (!isEmpty(itemsByGroupCode)) {
                // 如果字典项不为空则添加
                log.info("字典项为空，不添加字典组 queryForm={}",toJsonStr(queryForm));
                dictGroupItemDto.setItems(itemsByGroupCode);
                result.add(dictGroupItemDto);
            }
        }

        return result;
    }

    @Override
    public List<Dict> getGroupsByGroupCodes(DictGroupsQueryForm queryForm) {
        Assert.hasText(queryForm.getGroupCodes(),"字典组编码不能为空");

        return list(Wrappers.<Dict>lambdaQuery()
                .in(Dict::getCode,queryForm.getGroupCodes().split(","))
                .eq(!isStrEmpty(queryForm.getGroupFlag()),Dict::getGroupFlag,queryForm.getGroupFlag())
                .eq(Dict::getIsDisabled,false)
                .eq(Dict::getIsGroup,true)
                .and(wp->{
                    wp.eq(Dict::getIsPublic,true).or().eq(!isStrEmpty(queryForm.getPrivateFlag()),Dict::getPrivateFlag,queryForm.getPrivateFlag());
                })
        );
    }

    @Override
    public Dict getDictByCodeAndValue(String code, String value) {
        Dict byCode = getByCode(code);
        return getOne(Wrappers.<Dict>lambdaQuery().eq(Dict::getParentId,byCode.getId()).eq(Dict::getValue,value),false);
    }
    @Cacheable(cacheNames = {"DictServiceImplCache_getValueById"})
    @Override
    public String getValueById(String id) {
        Dict byId = getById(id);
        return Optional.ofNullable(byId).map(Dict::getValue).orElse(null);
    }
    @Cacheable(cacheNames = {"DictServiceImplCache_getNameById"})
    @Override
    public String getNameById(String id) {
        Dict byId = getById(id);
        return Optional.ofNullable(byId).map(Dict::getName).orElse(null);
    }

    @Cacheable(cacheNames = {"DictServiceImplCache_getById"})
    @Override
    public Dict getById(Serializable id) {
        return super.getById(id);
    }

    @Override
    public String getIdByGroupCodeAndValue(String groupCode, String value) {
        DictItemsQueryForm dictItemsQueryForm = new DictItemsQueryForm();
        dictItemsQueryForm.setGroupCode(groupCode);
        List<Dict> dicts = getItemsByGroupCode(dictItemsQueryForm);
        return dicts.stream().filter(item -> isEqual(item.getValue(), value)).findFirst().map(Dict::getId).orElse(null);
    }
}
